/*
 * Copyright (C) 2011-present ShenZhen iBOXCHAIN Information Technology Co.,Ltd.
 *
 * All right reserved.
 *
 * This software is the confidential and proprietary
 * information of iBOXCHAIN Company of China.
 * ("Confidential Information"). You shall not disclose
 * such Confidential Information and shall use it only
 * in accordance with the terms of the contract agreement
 * you entered into with iBOXCHAIN inc.
 */
package com.example.wac.shiro;

import org.apache.shiro.ShiroException;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.serializer.ObjectSerializer;
import org.crazycake.shiro.serializer.RedisSerializer;
import org.crazycake.shiro.serializer.StringSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author wuancheng
 * @description
 * @date 2023-04-14 18:19:00
 */

public abstract class AbstractLoadUrlPerms {
    protected static final Logger log = LoggerFactory.getLogger(AbstractLoadUrlPerms.class);
    protected RedisSerializer<String> keySerializer = new StringSerializer();
    protected RedisSerializer<Object> valueSerializer = new ObjectSerializer();
    @Value("${shiro.url.perms.key}")
    protected String shiroUrlPermsKey;
    @Value("${shiro.service.name}")
    protected String shiroServiceName;
    @Autowired(
            required = false
    )
    protected RedisManager redisManager;
    @Lazy
    @Autowired(
            required = false
    )
    private ShiroFilterFactoryBean shiroFilterFactoryBean;

    public AbstractLoadUrlPerms() {
    }

    public void updateFilterChain() {
        synchronized(this.shiroFilterFactoryBean) {
            AbstractShiroFilter shiroFilter;
            try {
                shiroFilter = (AbstractShiroFilter)this.shiroFilterFactoryBean.getObject();
            } catch (Exception var10) {
                throw new ShiroException("get ShiroFilter from shiroFilterFactoryBean error!");
            }

            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver)shiroFilter.getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager)filterChainResolver.getFilterChainManager();
            manager.getFilterChains().clear();
            this.shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            this.shiroFilterFactoryBean.setFilterChainDefinitionMap(this.getUrlPermsMap());
            Map<String, String> chains = this.shiroFilterFactoryBean.getFilterChainDefinitionMap();
            Iterator var7 = chains.entrySet().iterator();

            while(var7.hasNext()) {
                Map.Entry<String, String> entry = (Map.Entry)var7.next();
                String url = entry.getKey();
                String chainDefinition = (entry.getValue()).trim().replace(" ", "");
                manager.createChain(url, chainDefinition);
            }

            log.info("更新 Shiro过滤器链完成.");
        }
    }

    public void setServiceToFilterChainToRedis(Map<String, Map<String, String>> serviceToFilterChainMap) {
        try {
            byte[] k = this.keySerializer.serialize(this.shiroUrlPermsKey);
            byte[] value = this.valueSerializer.serialize(serviceToFilterChainMap);
            this.redisManager.set(k, value, -1);
        } catch (Exception var4) {
            log.error("set urlPerms to redis exception:", var4);
        }

    }

    protected Map<String, String> getDefaultUrlPermsMap() {
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap();
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/v1/login", "anon");
        filterChainDefinitionMap.put("/refresh/urlPerms", "anon");
        filterChainDefinitionMap.put("/healthCheck", "anon");
        filterChainDefinitionMap.put("/f5", "anon");
        filterChainDefinitionMap.put("/ignore_tk/v1/healthCheck.json", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/**", "authc");
        return filterChainDefinitionMap;
    }

    protected abstract Map<String, Map<String, String>> getServiceToFilterChainMap();

    public Map<String, String> getUrlPermsMap() {
        Map<String, Map<String, String>> serviceToFilterChainMap = this.getServiceToFilterChainMap();
        if (serviceToFilterChainMap != null && !serviceToFilterChainMap.isEmpty()) {
            Map<String, String> urlPermsMap = new LinkedHashMap();
            Map<String, String> baseShiroFilterMap = serviceToFilterChainMap.get("base_filter");
            Map<String, String> lastBaseShiroFilterMap = new LinkedHashMap(2);
            int i = 1;
            int size = baseShiroFilterMap.size();

            for(Iterator iterator = baseShiroFilterMap.entrySet().iterator(); iterator.hasNext(); ++i) {
                Map.Entry<String, String> entry = (Map.Entry)iterator.next();
                if (i == size) {
                    lastBaseShiroFilterMap.put(entry.getKey(), entry.getValue());
                    break;
                }

                urlPermsMap.put(entry.getKey(), entry.getValue());
            }

            Map<String, String> filterChainMap = serviceToFilterChainMap.get(this.shiroServiceName);
            if (filterChainMap != null && !filterChainMap.isEmpty()) {
                urlPermsMap.putAll(filterChainMap);
            }

            urlPermsMap.putAll(lastBaseShiroFilterMap);
            return urlPermsMap;
        } else {
            return this.getDefaultUrlPermsMap();
        }
    }
}

